import sys
import os
import json
import statistics
from typing import Dict, List
from datetime import datetime, timedelta
from .DataModels import UserPerformanceMetrics, QuestionDifficultyMetrics
from .QuestionEvaluation import QuestionEvaluator
import DataCollectionTools as DCTools
import BehaviorAnalysisTools as BATools
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
class UserEvaluator:
    def __init__(self, headers: dict = None):
        self.headers = headers
        self.user_metrics: Dict[str, UserPerformanceMetrics] = {}
        # 创建题目评价器实例用于题目难度分析
        self.question_evaluator = QuestionEvaluator(headers)
        # 五维权重配置
        self.weights = {
            'efficiency': 0.20,          # 效率能力
            'consistency': 0.20,         # 一致性表现
            'writeup_quality': 0.20,     # 题解质量
            'technical_skill': 0.20,     # 技术能力
            'progress_velocity': 0.20    # 进步速度
        }
    def calculate_user_metrics(self, user_id: str) -> UserPerformanceMetrics:
        """
        计算单个用户的性能指标
        Args:
            user_id (str): 用户ID
        Returns:
            UserPerformanceMetrics: 用户性能指标
        """
        metrics = UserPerformanceMetrics(user_id=user_id)
        # 获取题目列表
        question_list = DCTools.get_question_list(params={"user_id": user_id}, headers=self.headers)
        metrics.total_questions = len(question_list)
        if metrics.total_questions == 0:
            return metrics
        solved_questions = []
        total_attempts = 0
        resolution_times = []
        # 遍历每道题目分析用户表现
        for question in question_list:
            question_id = question.get("question_id")
            if not question_id:
                continue
            # 检查是否AC
            ac_status = BATools.get_question_ac_status(user_id, question_id, self.headers)
            if ac_status.get("is_ac", False):
                solved_questions.append(question_id)
                # 获取解题时间
                resolution_info = BATools.get_question_resolution_time(user_id, question_id, self.headers)
                if resolution_info and resolution_info.get("resolution_time"):
                    resolution_times.append(resolution_info["resolution_time"])
            # 统计尝试次数
            attempts = BATools.get_question_attempt_count(user_id, question_id, self.headers)
            total_attempts += attempts
        # 计算基础指标
        metrics.solved_questions = len(solved_questions)
        metrics.solved_question_ids = solved_questions
        metrics.solve_rate = metrics.solved_questions / metrics.total_questions
        metrics.total_attempts = total_attempts
        # 计算平均解题时间
        if resolution_times:
            metrics.average_resolution_time = sum(resolution_times, timedelta()) / len(resolution_times)
        # 计算各维度得分
        metrics.efficiency_score = self.calculate_efficiency_score(metrics)
        metrics.consistency_score = self.calculate_consistency_score(user_id, solved_questions)
        metrics.writeup_quality_score = self.calculate_writeup_quality_score(user_id, solved_questions)
        metrics.technical_skill_score = self.calculate_technical_skill_score(user_id, solved_questions)
        metrics.progress_velocity_score = self.calculate_progress_velocity_score(user_id, solved_questions)
        # 计算综合得分
        metrics.overall_score = self.calculate_overall_score(metrics)
        self.user_metrics[user_id] = metrics
        return metrics
    def calculate_efficiency_score(self, metrics: UserPerformanceMetrics) -> float:
        """
        计算效率得分
        Args:
            metrics (UserPerformanceMetrics): 用户指标
        Returns:
            float: 效率得分 (0-100)
        """
        if metrics.total_questions == 0:
            return 0.0
        # 基于解题率的基础分
        solve_rate_score = metrics.solve_rate * 60
        # 基于尝试次数的效率分 (尝试次数越少越好)
        if metrics.solved_questions > 0:
            avg_attempts_per_solved = metrics.total_attempts / metrics.solved_questions
            # 理想情况是每题1次尝试，超过3次尝试开始显著扣分
            attempt_efficiency = max(0, 40 - (avg_attempts_per_solved - 1) * 10)
        else:
            attempt_efficiency = 0
        return min(100, solve_rate_score + attempt_efficiency)
    def calculate_consistency_score(self, user_id: str, solved_questions: List[str]) -> float:
        """
        计算一致性得分 (基于解题时间的稳定性)
        Args:
            user_id (str): 用户ID
            solved_questions (List[str]): 已解决的题目列表
        Returns:
            float: 一致性得分 (0-100)
        """
        if len(solved_questions) < 2:
            return 50.0
        resolution_times = []
        for question_id in solved_questions:
            resolution_info = BATools.get_question_resolution_time(user_id, question_id, self.headers)
            if resolution_info and resolution_info.get("resolution_time"):
                # 转换为分钟数便于计算
                time_minutes = resolution_info["resolution_time"].total_seconds() / 60
                resolution_times.append(time_minutes)
        if len(resolution_times) < 2:
            return 50.0
        # 计算变异系数 (标准差/均值)
        mean_time = statistics.mean(resolution_times)
        if mean_time == 0:
            return 100.0
        std_time = statistics.stdev(resolution_times)
        cv = std_time / mean_time
        # 变异系数越小，一致性越好
        consistency_score = max(0, 100 - cv * 40)
        return min(100, consistency_score)
    def calculate_writeup_quality_score(self, user_id: str, solved_questions: List[str]) -> float:
        """
        计算题解质量得分
        Args:
            user_id (str): 用户ID
            solved_questions (List[str]): 已解决的题目列表
        Returns:
            float: 题解质量得分 (0-100)
        """
        if not solved_questions:
            return 0.0
        total_score = 0
        valid_reports = 0
        for question_id in solved_questions:
            try:
                writeup_report = DCTools.get_exist_writeup_report(
                    params={"user_id": user_id, "question_id": question_id},
                )
                writeup_report = writeup_report.get("writeup_report", "")
                writeup_report = json.loads(writeup_report)
                if writeup_report and writeup_report.get("score"):
                    total_score += writeup_report["score"]
                    valid_reports += 1
            except Exception:
                continue
        if valid_reports == 0:
            return 0.0
        return total_score / valid_reports
    def calculate_technical_skill_score(self, user_id: str, solved_questions: List[str]) -> float:
        """
        计算技术能力得分 (基于解决的题目难度)
        Args:
            user_id (str): 用户ID
            solved_questions (List[str]): 已解决的题目列表
        Returns:
            float: 技术能力得分 (0-100)
        """
        if not solved_questions:
            return 0.0
        total_difficulty_score = 0
        for question_id in solved_questions:
            # 获取题目难度指标
            question_metrics = self.question_evaluator.calculate_question_difficulty(question_id)
            if question_metrics:
                # 基于通过率计算难度分数 (通过率越低，难度越高，得分越高)
                difficulty_bonus = (1 - question_metrics.pass_rate) * 100
                total_difficulty_score += difficulty_bonus
        # 平均难度分数，并根据解题数量给予额外奖励
        base_score = total_difficulty_score / len(solved_questions) if solved_questions else 0
        # 解题数量奖励 (鼓励多做题)
        quantity_bonus = min(20, len(solved_questions) * 2)
        return min(100, base_score + quantity_bonus)
    def calculate_progress_velocity_score(self, user_id: str, solved_questions: List[str]) -> float:
        """
        计算进步速度得分
        Args:
            user_id (str): 用户ID
            solved_questions (List[str]): 已解决的题目列表
        Returns:
            float: 进步速度得分 (0-100)
        """
        if len(solved_questions) < 2:
            return 50.0  # 解题数量不足，返回中等分数
        # 获取用户的所有提交记录，按时间排序
        submission_data = self.get_user_submission_timeline(user_id)
        if not submission_data:
            return 50.0
        # 分析四个维度的进步速度
        time_improvement = self.analyze_time_improvement(submission_data)
        difficulty_progression = self.analyze_difficulty_progression(submission_data)
        success_rate_improvement = self.analyze_success_rate_improvement(submission_data)
        learning_curve_steepness = self.analyze_learning_curve_steepness(submission_data)
        # 综合计算进步速度得分
        progress_score = (
            time_improvement * 0.3 +           # 解题时间改善 30%
            difficulty_progression * 0.25 +     # 难度递进 25%
            success_rate_improvement * 0.25 +   # 成功率提升 25%
            learning_curve_steepness * 0.20     # 学习曲线陡峭度 20%
        )
        return min(100, max(0, progress_score))
    def get_user_submission_timeline(self, user_id: str) -> List[Dict]:
        """
        获取用户提交时间线数据
        Args:
            user_id (str): 用户ID
        Returns:
            List[Dict]: 按时间排序的提交记录
        """
        try:
            # 获取用户提交记录
            submission_data = DCTools.get_submissions(
                params={"user_id": user_id}, 
                headers=self.headers
            )
            if not submission_data:
                return []
            # 为每个提交记录添加题目难度信息
            timeline_data = []
            for submission in submission_data:
                question_id = submission.get("question_id")
                if question_id:
                    # 获取题目难度
                    question_metrics = self.question_evaluator.calculate_question_difficulty(question_id)
                    submission_record = {
                        "question_id": question_id,
                        "submit_time": submission.get("submit_time"),
                        "is_correct": submission.get("is_correct", False),
                        "resolution_time": submission.get("resolution_time"),
                        "difficulty_score": question_metrics.difficulty_score if question_metrics else 50.0
                    }
                    timeline_data.append(submission_record)
            # 按提交时间排序
            timeline_data.sort(key=lambda x: x["submit_time"] if x["submit_time"] else datetime.min)
            return timeline_data
        except Exception as e:
            print(f"获取用户提交时间线失败: {e}")
            return []
    def analyze_time_improvement(self, submission_data: List[Dict]) -> float:
        """
        分析解题时间改善趋势
        Args:
            submission_data (List[Dict]): 提交记录
        Returns:
            float: 时间改善得分 (0-100)
        """
        if len(submission_data) < 3:
            return 50.0
        # 只分析AC的提交记录
        ac_submissions = [s for s in submission_data if s["is_correct"] and s.get("resolution_time")]
        if len(ac_submissions) < 3:
            return 50.0
        # 计算时间改善趋势
        time_points = []
        for i, submission in enumerate(ac_submissions):
            if submission["resolution_time"]:
                time_minutes = submission["resolution_time"].total_seconds() / 60
                time_points.append((i, time_minutes))
        if len(time_points) < 3:
            return 50.0
        # 使用线性回归分析时间趋势
        n = len(time_points)
        sum_x = sum(point[0] for point in time_points)
        sum_y = sum(point[1] for point in time_points)
        sum_xy = sum(point[0] * point[1] for point in time_points)
        sum_x2 = sum(point[0] ** 2 for point in time_points)
        # 计算斜率
        if n * sum_x2 - sum_x ** 2 == 0:
            return 50.0
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        # 斜率为负表示时间在减少（进步）
        if slope < 0:
            improvement_score = min(100, 60 + abs(slope) * 10)
        else:
            improvement_score = max(0, 40 - slope * 10)
        return improvement_score
    def analyze_difficulty_progression(self, submission_data: List[Dict]) -> float:
        """
        分析难度递进趋势
        Args:
            submission_data (List[Dict]): 提交记录
        Returns:
            float: 难度递进得分 (0-100)
        """
        if len(submission_data) < 3:
            return 50.0
        # 只分析AC的提交记录
        ac_submissions = [s for s in submission_data if s["is_correct"]]
        if len(ac_submissions) < 3:
            return 50.0
        # 分析难度递进
        difficulty_points = []
        for i, submission in enumerate(ac_submissions):
            difficulty_points.append((i, submission["difficulty_score"]))
        if len(difficulty_points) < 3:
            return 50.0
        # 计算难度递进趋势
        n = len(difficulty_points)
        sum_x = sum(point[0] for point in difficulty_points)
        sum_y = sum(point[1] for point in difficulty_points)
        sum_xy = sum(point[0] * point[1] for point in difficulty_points)
        sum_x2 = sum(point[0] ** 2 for point in difficulty_points)
        if n * sum_x2 - sum_x ** 2 == 0:
            return 50.0
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        # 正斜率表示挑战更难的题目（进步）
        if slope > 0:
            progression_score = min(100, 60 + slope * 5)
        else:
            progression_score = max(0, 40 + slope * 5)
        return progression_score
    def analyze_success_rate_improvement(self, submission_data: List[Dict]) -> float:
        """
        分析成功率提升趋势
        Args:
            submission_data (List[Dict]): 提交记录
        Returns:
            float: 成功率提升得分 (0-100)
        """
        if len(submission_data) < 10:
            return 50.0
        # 将提交记录按时间分段，分析每段的成功率
        segment_size = max(5, len(submission_data) // 4)
        segments = []
        for i in range(0, len(submission_data), segment_size):
            segment = submission_data[i:i + segment_size]
            if len(segment) >= 3:
                success_count = sum(1 for s in segment if s["is_correct"])
                success_rate = success_count / len(segment)
                segments.append(success_rate)
        if len(segments) < 3:
            return 50.0
        # 计算成功率改善趋势
        rate_points = [(i, rate) for i, rate in enumerate(segments)]
        n = len(rate_points)
        sum_x = sum(point[0] for point in rate_points)
        sum_y = sum(point[1] for point in rate_points)
        sum_xy = sum(point[0] * point[1] for point in rate_points)
        sum_x2 = sum(point[0] ** 2 for point in rate_points)
        if n * sum_x2 - sum_x ** 2 == 0:
            return 50.0
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        # 正斜率表示成功率在提升
        if slope > 0:
            improvement_score = min(100, 60 + slope * 200)
        else:
            improvement_score = max(0, 40 + slope * 200)
        return improvement_score
    def analyze_learning_curve_steepness(self, submission_data: List[Dict]) -> float:
        """
        分析学习曲线陡峭度
        Args:
            submission_data (List[Dict]): 提交记录
        Returns:
            float: 学习曲线陡峭度得分 (0-100)
        """
        if len(submission_data) < 5:
            return 50.0
        # 计算累积解题数量的增长速度
        cumulative_solved = []
        solved_count = 0
        for i, submission in enumerate(submission_data):
            if submission["is_correct"]:
                solved_count += 1
            cumulative_solved.append((i, solved_count))
        if len(cumulative_solved) < 5:
            return 50.0
        # 分析学习曲线的加速度
        early_segment = cumulative_solved[:len(cumulative_solved)//2]
        late_segment = cumulative_solved[len(cumulative_solved)//2:]
        # 计算两段的斜率
        def calculate_slope(points):
            if len(points) < 2:
                return 0
            n = len(points)
            sum_x = sum(point[0] for point in points)
            sum_y = sum(point[1] for point in points)
            sum_xy = sum(point[0] * point[1] for point in points)
            sum_x2 = sum(point[0] ** 2 for point in points)
            if n * sum_x2 - sum_x ** 2 == 0:
                return 0
            return (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        early_slope = calculate_slope(early_segment)
        late_slope = calculate_slope(late_segment)
        # 学习曲线加速度：后期斜率比前期斜率大表示学习加速
        if early_slope > 0:
            acceleration = late_slope / early_slope
            if acceleration > 1:
                steepness_score = min(100, 60 + (acceleration - 1) * 50)
            else:
                steepness_score = max(0, 40 + (acceleration - 1) * 50)
        else:
            steepness_score = 50.0
        return steepness_score
    def calculate_overall_score(self, metrics: UserPerformanceMetrics) -> float:
        """
        计算五维综合得分
        Args:
            metrics (UserPerformanceMetrics): 用户指标
        Returns:
            float: 综合得分 (0-100)
        """
        score = (
            metrics.efficiency_score * self.weights['efficiency'] +
            metrics.consistency_score * self.weights['consistency'] +
            metrics.writeup_quality_score * self.weights['writeup_quality'] +
            metrics.technical_skill_score * self.weights['technical_skill'] +
            metrics.progress_velocity_score * self.weights['progress_velocity']
        )
        return min(100, score)